#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>

#include "peer.h"
#include "net.h"
#include "torrent.h"

extern BOOL g_exit;

int xx_peer_init(list_node **peer_list, fd_set *peer_fds)
{
	if ( NULL == peer_list || NULL == peer_fds) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return -1;
	}


	FD_ZERO(peer_fds);

	*peer_list = (list_node *)malloc(sizeof(list_node)); 
	if ( !*peer_list ) {
		return -1;
	}

	(*peer_list)->data = NULL;
	list_creat(*peer_list);

	return 0;
}

void *xx_peer_start(void *arg)
{
	xx_torrent			*torrent;
	xx_peer				*peer;
	list_node			*node;

	if ( NULL == arg ) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return NULL;
	}

	torrent = (xx_torrent *)arg;
	node = torrent->peer_list->next;
	while ( !g_exit ) {
		while ( node && node != torrent->peer_list){
			peer = (xx_peer *)(node->data);
			xx_peer_handle(peer);
		}

//		xx_peer_manager(torrent);

		usleep(3000);
	}

	return ((void *)0);
}

void xx_peer_handle(xx_peer *peer)
{
	if ( NULL == peer ) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return;
	}

	if ( peer->sockfd < 0 ) {
		xx_init_new_peer(peer);
	}

}

int	handshake(xx_peer *peer)
{
	char		buff[100] = {0};

	if ( NULL == peer ) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return -1;
	}

	memset(buff, 0, 100);

	sprintf(buff, "%d%s", 19, "BitTorrent protocol");
	sprintf(buff + 27, "%s%s", "info_hash", peer->peer_id);

	xx_writen(peer->sockfd, buff, 67);
	xx_readn(peer->sockfd, buff, 67);
	if ( memcmp("info_hash", buff + 27, 20) ) {
		return -1;
	}

	return 0;
}

int	xx_init_new_peer(xx_peer *peer)
{
	if ( NULL == peer ) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return -1;
	}

	peer->sockfd = xx_connect_host(NULL, NULL, 0, (struct sockaddr *)&peer->peer_addr);
	handshake(peer);
	return 0;
}

int	xx_peer_list_add(list_node *list_head, char *id, char *ip, int port, int *peer_num)
{
	int			 num;
	xx_peer		*peer = NULL;


	if ( NULL == list_head || NULL == id || NULL == ip || NULL == peer_num ) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return -1;
	}

	num = *peer_num;

	list_node *node = list_head->next;
	while ( node && node != list_head) {
		peer = (xx_peer *)node->data;
		if ( strlen(peer->peer_id) > 0 &&  strlen(peer->peer_id) == strlen(id) 
					&& 0 == strcmp(peer->peer_id, id) ) {
			return 1;
		}
		else if ( 0 == strcmp(inet_ntoa(peer->peer_addr.sin_addr), ip) ) {
			return 1;
		}

		node = node->next;
	}

	peer = (xx_peer *)malloc(sizeof(xx_peer));
	if ( !peer ) {
		return -1;
	}

	*peer_num = num + 1;

	memset(peer, 0, sizeof(peer));
	inet_aton(ip, &peer->peer_addr.sin_addr); 
	peer->peer_addr.sin_port = htons(port);

	peer->choke_state &= AM_CHOKING; 
	peer->choke_state &= PEER_CHOKING; 
	peer->choke_state |= ~AM_INTERESTED; 
	peer->choke_state |= ~PEER_INTERESTED; 

	peer->sockfd = -1;

	node = (list_node *)malloc(sizeof(list_node));
	node->data = peer; 
	list_add(list_head, node);
	return 0;
}

int	xx_peer_list_add2(list_node *list_head, in_addr_t ip, in_port_t port, int *peer_num)		//FIXME: make sure the length is right
{
	int			 num;
	xx_peer		*peer = NULL; 

	if ( NULL == list_head || NULL == peer_num ) {
		xx_dbg("Input para Invalid\n");
		xx_assert(0);
		return -1;
	}

	num = *peer_num;

	list_node *node = list_head->next;
	while ( node && node != list_head ) {
		peer = (xx_peer *)node->data;
		if ( peer->peer_addr.sin_addr.s_addr == ip ) {
			return 1;
		}

		node = node->next;
	}

	peer = (xx_peer *)malloc(sizeof(xx_peer));
	if ( !peer ) {
		return -1;
	}

	*peer_num = num + 1;

	memset(peer, 0, sizeof(peer));
	peer->peer_addr.sin_addr.s_addr = ip; 
	peer->peer_addr.sin_port = port;

	peer->choke_state &= AM_CHOKING; 
	peer->choke_state &= PEER_CHOKING; 
	peer->choke_state |= ~AM_INTERESTED; 
	peer->choke_state |= ~PEER_INTERESTED; 

	peer->sockfd = -1;

	node = (list_node *)malloc(sizeof(list_node));
	node->data = peer; 
	list_add(list_head, node);

	return 0;
}

int xx_mesg_keepalive(int chok_type, int sockfd)
{

	send(sockfd, "len=0000", strlen("len=0000"), MSG_WAITALL);

	return 0;
}

int xx_mesg_chok(int chok_type, int sockfd)
{
	char buff[20];

	memset(buff, 0, 20);
	sprintf(buff, "len=0001id=%d", chok_type);

	send(sockfd, buff, strlen(buff), MSG_WAITALL);

	return 0;
}

